﻿using System;
using System.Buffers;
using System.Threading;
using System.Threading.Tasks;
using TiffLibrary;

namespace WholeSlideImageLibrary.Formats.OptimizedPyramidTiledImage
{
    internal class OptimizedPyramidTiledImageIdentifier : IImageIdentifier
    {
        public string Name => "OptimizedPyramidTiledImage";

        public int HeaderSize => 32;

        public async ValueTask<ImageSourceType> IdentifyAsync(FileSourceInfo fileInfo, FileSourceReader reader, ReadOnlyMemory<byte> header, CancellationToken cancellationToken = default)
        {
            if (header.Length < 16)
            {
                return ImageSourceType.None;
            }

            // 是TIFF文件头吗？
            if (TiffFileHeader.TryParse(header.Span, out _))
            {
                // 真正的头部可能在后面，移动指针到后面去
                if (header.Length < 32)
                {
                    return ImageSourceType.None;
                }
                header = header.Slice(16);
            }
            if (!FileHeader.TryFindMainBlock(header.Span, fileInfo.FileSize, out long mainBlockPointer))
            {
                return ImageSourceType.None;
            }

            // 读取MainBlock
            byte[] buffer = ArrayPool<byte>.Shared.Rent(FileMainBlock.MarshalSize);
            try
            {
                int readCount = await reader.ReadAsync(mainBlockPointer, buffer.AsMemory(0, FileMainBlock.MarshalSize), cancellationToken).ConfigureAwait(false);
                if (readCount != FileMainBlock.MarshalSize || !FileMainBlock.TryParse(buffer.AsSpan(0, FileMainBlock.MarshalSize), fileInfo.FileSize, out _))
                {
                    return ImageSourceType.None;
                }

                return ImageSourceType.SingleImage;
            }
            finally
            {
                ArrayPool<byte>.Shared.Return(buffer);
            }
        }

        public ValueTask<ImageSourceType> IdentifyAsync(DirectorySourceInfo directoryInfo, CancellationToken cancellationToken = default)
        {
            return new ValueTask<ImageSourceType>(ImageSourceType.None);
        }

        public ValueTask<WholeSlideImageCollection?> OpenImageCollectionAsync(FileSourceInfo fileInfo, FileSourceReader reader, CancellationToken cancellationToken = default)
        {
            return default;
        }

        public ValueTask<WholeSlideImageCollection?> OpenImageCollectionAsync(DirectorySourceInfo directoryInfo, CancellationToken cancellationToken = default)
        {
            return default;
        }

        public async ValueTask<WholeSlideImage?> OpenSingleImageAsync(FileSourceInfo fileInfo, FileSourceReader reader, CancellationToken cancellationToken = default)
        {
            byte[] buffer = ArrayPool<byte>.Shared.Rent(256); // 256既可以装得下FileMainBlock.MarshalSize，也可以装得下文件头部，还可以作为smallbuffer使用
            try
            {
                int readCount = await reader.ReadAsync(0, buffer.AsMemory(0, 32), cancellationToken).ConfigureAwait(false);
                if (readCount < 16)
                {
                    return null;
                }

                // 是TIFF文件头吗？
                if (TiffFileHeader.TryParse(buffer.AsSpan(0, 16), out _))
                {
                    // 真正的头部可能在后面，把内容复制过来
                    if (readCount < 32)
                    {
                        return null;
                    }
                    Array.Copy(buffer, 16, buffer, 0, 16);
                }
                if (!FileHeader.TryFindMainBlock(buffer, fileInfo.FileSize, out long mainBlockPointer))
                {
                    return null;
                }

                return await OptimizedPyramidTiledWholeSlideImage.OpenAsync(fileInfo, reader, buffer, mainBlockPointer, cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                ArrayPool<byte>.Shared.Return(buffer);
            }
        }


        public ValueTask<WholeSlideImage?> OpenSingleImageAsync(DirectorySourceInfo directoryInfo, CancellationToken cancellationToken = default)
        {
            return default;
        }
    }
}
